use ndarray::Array2;

use crate::tiling::tiles::tile_list::TileList;
use crate::tiling::tiles::TileConnectionArray;
use crate::tiling::{Direction, GridSlot, MissingTilePolicy, TileSelectionPolicy, VacancyPolicy};

mod population;
#[cfg(test)]
pub(crate) mod tests;
mod output;

const DIRECTION_COUNTERPART_OFFSET_MAPPING: [(Direction, Direction, (isize, isize)); 4] = [
    (Direction::North, Direction::South, (-1, 0)),
    (Direction::East, Direction::West, (0, 1)),
    (Direction::South, Direction::North, (1, 0)),
    (Direction::West, Direction::East, (0, -1)),
];

const NORTH_SEEKING_DIRECTIONS: [(Direction, (isize, isize)); 4] = [
    (Direction::East, (0, 1)),
    (Direction::North, (-1, 0)),
    (Direction::West, (0, -1)),
    (Direction::South, (1, 0)),
];

const EAST_SEEKING_DIRECTIONS: [(Direction, (isize, isize)); 4] = [
    (Direction::South, (1, 0)),
    (Direction::East, (0, 1)),
    (Direction::North, (-1, 0)),
    (Direction::West, (0, -1)),
];

const SOUTH_SEEKING_DIRECTIONS: [(Direction, (isize, isize)); 4] = [
    (Direction::West, (0, -1)),
    (Direction::South, (1, 0)),
    (Direction::East, (0, 1)),
    (Direction::North, (-1, 0)),
];

const WEST_SEEKING_DIRECTIONS: [(Direction, (isize, isize)); 4] = [
    (Direction::North, (-1, 0)),
    (Direction::West, (0, -1)),
    (Direction::South, (1, 0)),
    (Direction::East, (0, 1)),
];

#[cfg_attr(test, derive(Debug, PartialEq))]
pub(crate) struct SlotGrid {
    grid: Array2<Option<GridSlot>>,
    tile_list: TileList,
    tile_connections: TileConnectionArray,
    border_tile_id: Option<usize>,
    missing_tile_policy: MissingTilePolicy,
    tile_selection_policy: TileSelectionPolicy,
    vacancy_policy: VacancyPolicy,
    // num_rows and num_cols signify the number of visible rows/columns and are stored for ease of
    // access.
    num_rows: usize,
    num_cols: usize,
    current_slot: (usize, usize),
    current_predecessor: Option<(usize, usize)>,
    last_leaves: Vec<(usize, usize)>,
    exposed_edge_count: usize,
}
